package com.cl.short_video_java.util;

import com.cl.short_video_java.config.FfmpegConfig;
import lombok.extern.slf4j.Slf4j;
import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.ffmpeg.global.avutil;
import org.bytedeco.javacv.*;

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

@Slf4j
public class FfmpegUtil {


	public static void changeMediaToM3u8(InputStream inputStream, String m3u8Url, String infoUrl) throws IOException {
		// 构造ts文件输出地址
		String filePath = m3u8Url.substring(0, m3u8Url.lastIndexOf("\\") - 1);// 视频总文件夹路径
		String tmp = m3u8Url.substring(m3u8Url.lastIndexOf("\\") + 1);
		String fileName = tmp.substring(0, tmp.lastIndexOf("-"));// 文件夹名

//        CreateDirectoryUtil.createDirectory(filePath);// 以下测试用
		log.info("m3u8Url: {}", m3u8Url); // 打印完整的m3u8Url
		log.info("filePath: {}", filePath); // 打印文件路径
		log.info("tmp: {}", tmp);
		log.info("folderName: {}", fileName); // 打印文件夹名称
		log.info(filePath + "\\" + fileName + "-%d.ts");// 文件真实地址

		avutil.av_log_set_level(avutil.AV_LOG_DEBUG);// 设置Ffmpeg日志级别为debug级别
		FFmpegLogCallback.set();// 设置Ffmpeg日志回调

		// 创建FfmpegFrameGrabber对象，用于从输入流中抓取帧
		FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(inputStream);
		grabber.start();// 开始抓取

		// 创建FfmpegFrameRecorder对象，用于录制M3U8格式的视频
		FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(
				m3u8Url,// m3u8文件输出地址，也可设置为请求上传地址（需准备好请求api）
				grabber.getImageWidth(),
				grabber.getImageHeight(),
				grabber.getAudioChannels());

		recorder.setFormat("hls");// 设置输出格式为HLS（HTTP Live Streaming）
		recorder.setOption("hls_time", "5");// 设置每个HLS片段的时间长度为5秒
		recorder.setOption("hls_list_size", "0");// 设置播放列表中的片段数量，0表示不限制
		recorder.setOption("hls_flags", "delete_segments");// 设置删除旧片段的标志
		recorder.setOption("hls_delete_threshold", "1");// 设置删除片段的阈值
		recorder.setOption("hls_segment_type", "mpegts");// 设置HLS片段的类型为mpegts
		recorder.setOption("hls_segment_filename", filePath + "\\" + fileName + "-%d.ts");// 设置HLS片段的文件名模板，%d会被替换为序列号 ts文件输出地址

//        recorder.setOption("hls_key_info_file", infoUrl);// 设置密钥信息文件的URL，酌情设置

		// 设置请求上传方式为POST
//        recorder.setOption("method", "POST");// 将输出片段通过请求上传时设置

		recorder.setGopSize((int) grabber.getFrameRate()); // 尝试将 GOP 设置为帧率的整数倍
		recorder.setFrameRate(grabber.getFrameRate()); // 确保帧率与源视频一致
		recorder.setVideoQuality(1.0);// 设置视频质量（1.0表示无损）
		recorder.setVideoBitrate(1920 * 1080);// 设置视频比特率，此设置可调清晰度
		recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);// 设置视频编码器为H264
		recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC); // 设置音频编码器
		recorder.setAudioChannels(grabber.getAudioChannels()); // 设置音频通道数
		recorder.setSampleRate(grabber.getSampleRate()); // 设置音频采样率
		recorder.start();// 开始录制

		// 循环抓取帧并录制
		Frame frame;
		while ((frame = grabber.grab()) != null) {
			if (frame.image != null) {
				// 处理视频帧
				recorder.record(frame);
			} else if (frame.samples != null) {
				// 处理音频帧
				recorder.record(frame);
			}
		}
		recorder.setTimestamp(grabber.getTimestamp());// 设置录制结束的时间戳
		// 关闭录制器和抓取器
		try {
			recorder.close();
			grabber.close();
		} catch (FrameRecorder.Exception | FrameGrabber.Exception e) {
			log.error("Error closing recorder or grabber", e);
		}
	}

	// 重载方法，支持默认地址输出
	public static void changeMediaToM3u8(InputStream inputStream) throws IOException {
		changeMediaToM3u8(inputStream, FfmpegConfig.VIDEOS_FOLDER + "\\" + UUID.randomUUID() + "-video.m3u8", FfmpegConfig.INFO_PROFILES_PATH);
	}


	public static String mergeVideo(List<File> partFiles, File outputFile, String ffmpegPath) throws IOException {
		// FFmpeg可执行文件的路径，需要根据实际情况修改
		List<String> command = new ArrayList<>();
		command.add("ffmpeg");
		command.add("-i");
		// 使用concat协议来合并文件，需要将文件路径用竖线"|"连接
		String concatFiles = "concat:"+ String.join("|", partFiles.stream().map(File::getAbsolutePath).toArray(String[]::new));
		command.add(concatFiles);
		command.add("-c");
		command.add("copy");
		command.add(outputFile.getAbsolutePath());
		ProcessBuilder processBuilder = new ProcessBuilder(command);
		try {
			Process process = processBuilder.start();
			// 处理标准输出流
			new Thread(() -> {
				try {
					java.io.BufferedReader reader = new java.io.BufferedReader(new java.io.InputStreamReader(process.getInputStream()));
					String line;
					while ((line = reader.readLine()) != null) {
						System.out.println("标准输出: " + line);
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
			}).start();
			// 处理标准错误输出流
			new Thread(() -> {
				try {
					java.io.BufferedReader reader = new java.io.BufferedReader(new java.io.InputStreamReader(process.getErrorStream()));
					String line;
					while ((line = reader.readLine()) != null) {
						log.info("标准错误输出: " + line);
					}
				} catch (IOException e) {
					log.info(e.getMessage());
				}
			}).start();
			int exitCode = process.waitFor();
			if (exitCode == 0) {
				log.info("合并成功");
				return "1";

			} else {
				log.info("合并失败");
				return "0";
			}
		} catch (IOException | InterruptedException e) {
			log.info(e.getMessage());
			return "0";
		}
	}

	public static String videoFrame(File inpuFile, File outFile, String ffmpegPath) {
		System.out.println("--------------------" + inpuFile.getAbsolutePath());
		try {
			// 假设视频文件名为input.mp4
			ProcessBuilder pb = new ProcessBuilder("ffmpeg", "-i", inpuFile.toString(), "-ss", "00:00:02", "-vframes", "1", outFile.toString());
			pb.inheritIO();
			Process process = pb.start();
			process.waitFor();
			//上传图片
			return outFile.getName();
		} catch (Exception e) {
			log.info(e.getMessage());
			return "0";
		}
	}
}
